#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019/1/19 13:53
# @Author  : Seven
# @File    : 2-edgeDemo.py
# @Software: PyCharm
# function : 以Lena为原始图像，通过OpenCV使用Sobel及Canny算子检测，比较边缘检测结果。
import cv2


def sobelEdge(img, name):
    """
    使用Sobel算子进行边缘检测
    :param img:
    :return:
    """
    # 先检测xy方向上的边缘
    Sobel_Ex = cv2.Sobel(src=img, ddepth=cv2.CV_16S, dx=1, dy=0, ksize=3)
    Sobel_Ey = cv2.Sobel(src=img, ddepth=cv2.CV_16S, dx=0, dy=1, ksize=3)
    # 即Sobel函数求完导数后会有负值，还有会大于255的值。而原图像是uint8，即8位无符号数，
    # 所以Sobel建立的图像位数不够，会有截断。因此要使用16位有符号的数据类型，即cv2.CV_16S。
    # 图像的每一个像素的横向及纵向梯度近似值结合
    # 用convertScaleAbs()函数将其转回原来的uint8形式。否则将无法显示图像，而只是一副灰色的窗口。
    absX = cv2.convertScaleAbs(Sobel_Ex)
    absY = cv2.convertScaleAbs(Sobel_Ey)
    SobelImage = cv2.addWeighted(absX, 0.5, absY, 0.5, 0)
    cv2.imshow("sobel-%s" % name, SobelImage)


def cannyEdge(img, name):
    """
    使用canny算子进行边缘检测
    :param img:
    :return:
    """
    # 边缘检测，最大阈值为150，最小阈值为50
    # Canny 推荐的 高:低 阈值比在 2:1 到3:1之间。
    cannyImage = cv2.Canny(img, 50, 150)
    cv2.imshow("canny-%s" % name, cannyImage)


if __name__ == '__main__':
    image = cv2.imread('image/lena.jpg')
    image = cv2.pyrDown(image)
    grayImage = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    cv2.imshow('source', image)
    # sobel算子--彩色图/灰度图
    sobelEdge(image, 'RGB')
    sobelEdge(grayImage, 'GRAY')
    # canny 算子--彩色图/灰度图
    cannyEdge(image, 'RGB')
    cannyEdge(grayImage, 'GRAY')

    cv2.waitKey(0)

# sobel算子对灰度渐变和噪声较多的图像处理效果比较好，同时对边缘定位比较准确

# canny不容易受噪声的干扰，能够检测真正的弱边缘。
